

use lang_c::ast::*;

use crate::{constant::*, plantuml::Plantuml};


impl<'a> Plantuml<'a> {

    pub fn plantuml_start(&mut self) {
        self.plantuml.push_str(PLANT_TOKEN_START);
    }

    pub fn plantuml_end(&mut self){

        if self.plantuml.ends_with(PLANT_TOKEN_STOP) {
            self.plantuml.push_str(PLANT_TOKEN_END);
        }
        else {
            self.plantuml.push_str(PLANT_TOKEN_STOP);
            self.plantuml.push_str(PLANT_TOKEN_END);
        }
    }

    pub fn plantuml_node(&mut self,name : &str) 
    {
        self.plantuml.push_str(format!(":{};",name).as_str());
    }

    pub fn plantuml_statement_start(&mut self)
    {
        // println!("{}",&self.plantuml);
        // println!("endwith : {}",self.plantuml.ends_with(PLANT_TOKEN_STMT_START));
        if !self.plantuml.ends_with(PLANT_TOKEN_STMT_START) {
            self.plantuml.push_str(PLANT_TOKEN_STMT_START);
        }
    }

    pub fn plantuml_color_begin(&mut self,color:&str)
    {
        let color_str =format!("<color:{}>",color);
        self.plantuml.push_str(&color_str);
    }

    pub fn plantuml_background_color(&mut self,color:&str)
    {
        let color_str =format!("#{}",color);
        self.plantuml.push_str(&color_str);
    }

    pub fn plantuml_color_end(&mut self)
    {
        self.plantuml.push_str("</color>");
    }

    pub fn plantuml_statement_end(&mut self)
    {
        if !self.plantuml.ends_with(PLANT_TOKEN_STMT_END) 
            && !self.plantuml.ends_with(PLANT_TOKEN_ENDIF) 
            && !self.plantuml.ends_with(PLANT_TOKEN_DETACH)
            && !self.plantuml.ends_with(PLANT_TOKEN_STOP)
            && !self.plantuml.ends_with(PLANT_TOKEN_ENDWHILE)
            && !self.plantuml.ends_with(PLANT_TOKEN_ENDSWITCH)
        {
            self.plantuml.push_str(PLANT_TOKEN_STMT_END);
            if self.need_flush_delay_plantuml() {
                self.plantuml_flush_dealyed()
            }
        }

        //dwj
        if self.need_delay_pop() {
            self.plantuml_pop(*self.delay_pop);
            *self.delay_pop = 0;
        }
    }
    

    pub fn plantuml_flag(&mut self,s:&str) {
        print!("in_function_scope: {} ",self.state.in_function_scope);
        print!("in_function_declarator: {} ",self.state.in_function_declarator);
        print!("in_function_indentifier_once: {} ",self.state.in_function_indentifier_once);
        print!("in_declarator_kind: {} ",self.state.in_declarator_kind);
        println!("identifier: {} ",s);

    }

    pub fn plantuml_function_identifier(&mut self, s: &str)
    {
        // self.plantuml_flag(s);
        // println!("plantuml_function_identifier");
        if self.state.in_function_declarator && self.state.in_function_scope && self.state.in_function_indentifier_once && self.state.in_declarator_kind {
            self.state.in_function_indentifier_once = false;
            // self.plantuml_node(s);
            self.plantuml_function_name.push_str(s);
        }

    }

    pub fn plantuml_identifier(&mut self,s:&str)
    {
        // if self.state.in_statement_scope  && !self.state.in_label_statement && !self.state.in_member_operator {//skip goto
        
        // if self.state.in_label_statement {
        //     self.plantuml.push_str(format!(" {}",s).as_str());
        //     self.plantuml_statement_end();
        //     self.plantuml_newline();
        // }

        if self.state.in_member_operator {
            self.plantuml.push_str(format!("{}",s).as_str());
        }
        
        if self.state.in_statement_scope && !self.state.in_member_operator {//skip goto
            self.plantuml.push_str(format!(" {}",s).as_str());
        }

  
    }

    pub fn plantuml_member_operator(&mut self, m:& MemberOperator)
    {
        match *m {
            MemberOperator::Direct => {
            },
            MemberOperator::Indirect => {
                self.plantuml.push_str(PLANT_STMT_INDIRECT);
            },
        }
    }

    pub fn plantuml_const(&mut self,constant:&Constant)
    {
        match *constant {
            Constant::Integer(ref i) => {self.plantuml.push_str(String::from(i.number.clone()).as_str());},
            Constant::Float(ref f) => {self.plantuml.push_str(String::from(f.number.clone()).as_str());},
            Constant::Character(_) => {}
        }
    }

    pub fn plantuml_type_name(&mut self,n: &TypeName)
    {
        // self.plantuml.push_str(n.)
    }

    pub fn plantuml_newline(&mut self)
    {
        self.plantuml.push_str("\n");
    }

    pub fn plantuml_type_specifier(&mut self,n:&TypeSpecifier)
    {
        if self.state.in_statement_scope {

            match n {
                TypeSpecifier::Void => self.plantuml.push_str(" void"),
                TypeSpecifier::Char => self.plantuml.push_str(" char"),
                TypeSpecifier::Short => self.plantuml.push_str(" short"),
                TypeSpecifier::Int => self.plantuml.push_str(" int"),
                TypeSpecifier::Long => self.plantuml.push_str(" long"),
                TypeSpecifier::Float => self.plantuml.push_str(" float"),
                TypeSpecifier::Double => self.plantuml.push_str(" double"),
                TypeSpecifier::Signed => self.plantuml.push_str(" signed"),
                TypeSpecifier::Unsigned => self.plantuml.push_str(" unsigned"),
                TypeSpecifier::Complex => self.plantuml.push_str(" complex"),
                TypeSpecifier::Atomic(_) => self.plantuml.push_str(" atomic"),
                TypeSpecifier::Struct(node) => self.plantuml.push_str(" struct"),
                TypeSpecifier::Enum(node) => self.plantuml.push_str(" enum"),
                TypeSpecifier::Bool => self.plantuml.push_str(" bool"),
                // TypeSpecifier::TypedefName(node) => todo!(),
                // TypeSpecifier::TypeOf(node) => todo!(),
                // TypeSpecifier::TS18661Float(ts18661_float_type) => todo!(),
        
                _ => {}
            }
        }

    
    }

    pub fn plantuml_storage_class_specifier(&mut self, n:&StorageClassSpecifier)
    {

        if self.state.in_statement_scope {
            match *n {
                StorageClassSpecifier::Typedef => self.plantuml.push_str("typedef"),
                StorageClassSpecifier::Extern => self.plantuml.push_str("extern"),
                StorageClassSpecifier::Static => self.plantuml.push_str("static"),
                StorageClassSpecifier::ThreadLocal => self.plantuml.push_str("threadLocal"),
                StorageClassSpecifier::Auto => self.plantuml.push_str("auto"),
                StorageClassSpecifier::Register => self.plantuml.push_str("register"),
            }
        }

    }

    pub fn plantuml_derived_declarator(&mut self,n:&DerivedDeclarator)
    {
        if self.state.in_statement_scope {
            match *n {
                DerivedDeclarator::Pointer(_) => self.plantuml.push_str(" *"),
                // DerivedDeclarator::KRFunction(_) => p.w.write_str(" KRFunction").unwrap(),
                // DerivedDeclarator::Block(_) => p.w.write_str(" Block").unwrap(),
                _ => {}
            }
        }
    }

    pub fn plantuml_array_declarator(&mut self, n:&ArrayDeclarator)
    {
        self.plantuml.push_str("[]");
    }

    pub fn plantuml_initializer(&mut self,n:&Initializer)
    {
        self.plantuml.push_str(" =");
    }

    pub fn plantuml_binary_operator(&mut self, n:&BinaryOperator)
    {
        match *n {
            BinaryOperator::Index => self.plantuml.push_str("Index"),
            BinaryOperator::Multiply => self.plantuml.push_str("*"),
            BinaryOperator::Divide => self.plantuml.push_str("/"),
            BinaryOperator::Modulo => self.plantuml.push_str("%"),
            BinaryOperator::Plus => self.plantuml.push_str("+"),
            BinaryOperator::Minus => self.plantuml.push_str("-"),
            BinaryOperator::ShiftLeft => self.plantuml.push_str("<<"),
            BinaryOperator::ShiftRight => self.plantuml.push_str(">>"),
            BinaryOperator::Less => self.plantuml.push_str("<"),
            BinaryOperator::Greater => self.plantuml.push_str(">"),
            BinaryOperator::LessOrEqual => self.plantuml.push_str("<="),
            BinaryOperator::GreaterOrEqual => self.plantuml.push_str(" >="),
            BinaryOperator::Equals => self.plantuml.push_str("=="),
            BinaryOperator::NotEquals => self.plantuml.push_str("!="),
            BinaryOperator::BitwiseAnd => self.plantuml.push_str("&"),
            BinaryOperator::BitwiseXor => self.plantuml.push_str("^"),
            BinaryOperator::BitwiseOr => self.plantuml.push_str("|"),
            BinaryOperator::LogicalAnd => self.plantuml.push_str(" &&"),
            BinaryOperator::LogicalOr => self.plantuml.push_str("||"),
            BinaryOperator::Assign => self.plantuml.push_str(" ="),
            BinaryOperator::AssignMultiply => self.plantuml.push_str("*="),
            BinaryOperator::AssignDivide => self.plantuml.push_str("/="),
            BinaryOperator::AssignModulo => self.plantuml.push_str("%/"),
            BinaryOperator::AssignPlus => self.plantuml.push_str("+="),
            BinaryOperator::AssignMinus => self.plantuml.push_str("-="),
            BinaryOperator::AssignShiftLeft => self.plantuml.push_str("<<="),
            BinaryOperator::AssignShiftRight => self.plantuml.push_str(">>="),
            BinaryOperator::AssignBitwiseAnd => self.plantuml.push_str("&="),
            BinaryOperator::AssignBitwiseXor => self.plantuml.push_str("^="),
            BinaryOperator::AssignBitwiseOr => self.plantuml.push_str("|="),
        };
    }

    pub fn plantuml_bracket_begin(&mut self){
        self.plantuml.push_str("(");
    }

    pub fn plantuml_bracket_end(&mut self){
        self.plantuml.push_str(")");
    }

    pub fn plantuml_comma(&mut self){
        self.plantuml.push_str(",");
    }

    pub fn plantuml_pop(&mut self,count:usize)
    {
        for i in 0..count {
            self.plantuml.pop();
        }
    }

    pub fn plantuml_unary_operator(&mut self,n:&UnaryOperator){ 
        match *n {
            UnaryOperator::PostIncrement => {
                self.plantuml.push_str("++");
            },
            UnaryOperator::PostDecrement => {
                self.plantuml.push_str("--");
            },
            UnaryOperator::PreIncrement => {self.plantuml.push_str("++");},
            UnaryOperator::PreDecrement => {self.plantuml.push_str("--");},
            UnaryOperator::Address => {"Address";},
            UnaryOperator::Indirection => {"Indirection";},
            UnaryOperator::Plus => {self.plantuml.push_str("+");},
            UnaryOperator::Minus => {self.plantuml.push_str("-");},
            UnaryOperator::Complement => {self.plantuml.push_str("~");},
            UnaryOperator::Negate => {self.plantuml.push_str("!");},
        }

    }

    pub fn plantuml_if(&mut self)
    {
        self.plantuml.push_str(PLANT_TOKEN_IF);
    }

    pub fn plantuml_else(&mut self){
        self.plantuml.push_str(PLANT_TOKEN_ELSE);
    }

    pub fn plantuml_while(&mut self) {
        self.plantuml.push_str(PLANT_TOKEN_WHILE);
    }

    pub fn plantuml_endwhile(&mut self) {
        self.plantuml.push_str(PLANT_TOKEN_ENDWHILE);
    }

    pub fn plantuml_do(&mut self)
    {
        self.plantuml.push_str(PLANT_TOKEN_DO);
    }

    pub fn plantuml_do_end(&mut self)
    {
        self.plantuml.push_str(PLANT_TOKEN_END_DO);
    }


    pub fn plantuml_brace_begin(&mut self) 
    {
        self.plantuml.push_str("{\n");

    }

    pub fn plantuml_brace_end(&mut self){
        self.plantuml.push_str("}\n");
    }


    pub fn plantuml_then_begin(&mut self) 
    {
        self.plantuml.push_str(PLANT_TOEKN_THEN);

    }

    pub fn plantuml_yes_condition(&mut self){
        self.plantuml.push_str(PLANT_TOKEN_YES_CONDITION);
    }

    pub fn plantuml_no_condition(&mut self){
        self.plantuml.push_str(PLANT_TOKEN_NO_CONDITION);
    }

    pub fn plantuml_then_end(&mut self){
        self.plantuml.push_str(PLANT_TOKEN_ENDIF);

    }

    pub fn plantuml_return(&mut self)
    {
        self.plantuml.push_str(PLANT_STMT_RETURN);
    }

    pub fn plantuml_goto(&mut self)
    {
        self.plantuml.push_str(PLANT_STMT_GOTO);
    }

    pub fn plantuml_delay_detach(&mut self)
    {
        self.delay_plantuml.push_str(PLANT_TOKEN_DETACH);
    }

    pub fn plantuml_delay_stop(&mut self)
    {
        self.delay_plantuml.push_str(PLANT_TOKEN_STOP);
    }

    pub fn plantuml_switch(&mut self)
    {
        self.plantuml.push_str(PLANT_TOKEN_SWITCH);
    }

    pub fn plantuml_case(&mut self){
        self.plantuml.push_str(PLANT_TOKEN_CASE);
    }

    pub fn plantuml_default(&mut self) {
        self.plantuml.push_str(PLANT_STMT_DEFAULT);
    }

    pub fn plantuml_endswitch(&mut self){

        self.plantuml.push_str(PLANT_TOKEN_ENDSWITCH);
    }

    fn plantuml_flush_dealyed(&mut self)
    {
        self.plantuml.push_str(self.delay_plantuml);
        self.delay_plantuml.clear();
    }

    

    fn need_flush_delay_plantuml(&mut self) -> bool {
        if(self.delay_plantuml.is_empty()){
            return false;
        } else {
            return true
        }
    }


    pub fn plantuml_delay_pop(&mut self, pop:usize){
        *self.delay_pop = pop;
    }

    fn need_delay_pop(&mut self) -> bool {
        if(*self.delay_pop !=0 ){
            return true
        } else {
            return false;

        }
    }



  

}
